#pragma once
#include "../gl/Application.h"
#include "model.h"
#include "GL/glxmd.h"
#include "view.h"

class StlApplication: public GlApplication {
private:
    Cube * model;
    View * view;
    Controller * controller;
public:

    StlApplication(int argc, char **argv) : GlApplication(argc, argv, false) {
        this->model = new Cube();
        this->controller = new Controller(this->model);
        this->view = new View(this->model);
    }

    ~StlApplication() {
        delete this->model;
        delete this->view;
        delete this->controller;
    }

    void draw() override {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers
        glMatrixMode(GL_MODELVIEW);     // To operate on model-view matrix
        glLoadIdentity();                 // Reset the model-view matrix

        this->view->draw();
        glutSwapBuffers();  // Swap the front and back frame buffers (double buffering)
    }

    void on_timer(int id) override {
        this->view->inc_rotation();
        this->init_timer(0, 50);

        if (!this->view->isMoved())
            this->view->startMove(this->controller->getNextStep());

        glutPostRedisplay();
    }

    void on_key_down(int key, bool spec, int x, int y) override {
        printf("key: %d, spec: %d\n", key, spec);
        if (spec) {

        } else {
            switch (key) {
                case 27: //esc
                    delete this;
                    exit(0);
                case 'r':
                    if (!this->view->isMoved())
                        this->view->startMove(ST_R);
                    break;
                case 18:
                    if (!this->view->isMoved())
                        this->view->startMove(ST_Rb);
                    break;
                case 'u':
                    if (!this->view->isMoved())
                        this->view->startMove(ST_U);
                    break;
                case 21:
                    if (!this->view->isMoved())
                        this->view->startMove(ST_Ub);
                    break;
                case 'l':
                    if (!this->view->isMoved())
                        this->view->startMove(ST_L);
                    break;
                case 12:
                    if (!this->view->isMoved())
                        this->view->startMove(ST_Lb);
                    break;
                case 'd':
                    if (!this->view->isMoved())
                        this->view->startMove(ST_D);
                    break;
                case 4:
                    if (!this->view->isMoved())
                        this->view->startMove(ST_Db);
                    break;
                case 'f':
                    if (!this->view->isMoved())
                        this->view->startMove(ST_F);
                    break;
                case 6:
                    if (!this->view->isMoved())
                        this->view->startMove(ST_Fb);
                    break;
                case 'b':
                    if (!this->view->isMoved())
                        this->view->startMove(ST_B);
                    break;
                case 2:
                    if (!this->view->isMoved())
                        this->view->startMove(ST_Bb);
                    break;
            }
        }
    }

    virtual void on_mouse(int button, int state, int x, int y) {
        if (state==0) switch (button) {
            case 4: //W_F
                this->view->inc_translate(true);
                break;
            case 3: //W_b
                this->view->inc_translate(false);
                    break;
        }
        printf("%d %d %d %d\n", button, state, x, y);
    }
protected:
    void create_scene() override {
        glClearDepth(1.0f);                   // Set background depth to farthest
        glShadeModel(GL_SMOOTH);   // Enable smooth shading
        glDepthFunc(GL_LESS);
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  // Nice perspective corrections
        // цвет фона
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Set background color to black and opaque
        // рассчет освещения
        glEnable(GL_LIGHTING);
        // двухсторонний расчет освещения
        glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
        // автоматическое приведение нормалей к
        // единичной длине
        glEnable(GL_NORMALIZE);

        //glClearDepth(1.0f);                   // Set background depth to farthest
        glEnable(GL_DEPTH_TEST);   // Enable depth testing for z-culling
        glDepthFunc(GL_LEQUAL);    // Set the type of depth-test
        glShadeModel(GL_SMOOTH);   // Enable smooth shading
        glEnable(GL_MULTISAMPLE);


        float bluish[4] = { 1, 1, 1, 1 };
        glLightfv(GL_LIGHT1, GL_DIFFUSE, bluish);
        glLightfv(GL_LIGHT1, GL_SPECULAR, bluish);
        float position[4] = { 0,0,0,-5 };
        glLightfv(GL_LIGHT1, GL_POSITION, position);
        glEnable(GL_LIGHT1);
        GLfloat spec[4] = { 0.5, 0.5, 0.5, 1 };
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
        glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 5);

    }

    void pre_loop() override {



        this->init_timer(0, 100);
    }

    GlWindow * createWindow() override {
        auto * window = new GlWindow(800, 200, 800, 800, "Cube");
        return window;
    }

    void releaseResources() override {
    }

    void createResources() override {
    }

};
